#ifndef GTL_STRUCTURES_HEADER_GUARD
#define GTL_STRUCTURES_HEADER_GUARD

#include <eastl/list.h>
#include <eastl/map.h>
#include <eastl/vector.h>
#include <eastl/string.h>

//#define GTL_DEBUG_STRUCTURES

#ifdef GTL_DEBUG_STRUCTURES
#include <map> 
#include <list> 
#endif

namespace GTL
{
	namespace Structures
	{
		class DataNode
		{
		public:
			enum NodeType
			{
				NONE = 0,
				NUMBER,
				STRING,
				LIST,
				DICT,
			};

#ifdef GTL_DEBUG_STRUCTURES
			typedef std::map<eastl::string, DataNode*> DictType;
			typedef std::list<DataNode*> ListType;
#else
			typedef eastl::map<eastl::string, DataNode*> DictType;
			typedef eastl::list<DataNode*> ListType;
#endif

			eastl::string String;
			DictType Dict;
			ListType List;
			double Number;

			NodeType Type;

			//eastl::string ToString() const;

			bool IsString(const char* str) const;

      eastl::string ValueAsString(const char* default = "") const;
      double ValueAsNumber(double default = 0.0) const;

      /// TODO: Check what's faster, indexing by string or char*
      bool HasElement(const char* key) const;
      bool ElementHasStringValue(const char* key, const char* val) const;

			const DataNode* GetElement(const char* key) const;
			const DataNode* GetElementSafe(const char* key) const;

      double GetElementAsNumber(const char* key, double default = 0.0) const;
      eastl::string GetElementAsString(const char* key, const char* default = "") const;

      template <typename T>
      bool GetElementIfExists(const char* key, T* val) const
      {
        if (!val) return false;

        const DataNode* node = GetElement(key);
        if (node)
        {
          *val = (T)node->ValueAsNumber();
          return true;
        }
        return false;
      }
      template <>
      bool GetElementIfExists(const char* key, eastl::string* val) const
      {
        if (!val) return false;

        const DataNode* node = GetElement(key);
        if (node)
        {
          *val = node->ValueAsString();
          return true;
        }
        return false;
      }
      template <>
      bool GetElementIfExists(const char* key, bool* val) const
      {
        if (!val) return false;

        const DataNode* node = GetElement(key);
        if (node && node->Type == NUMBER)
        {
          *val = node->Number != 0.0;
          return true;
        }
        return false;
      }

			DataNode() : String(), Number(0), Type(NONE) {}
			DataNode(const char* str) : String(str), Number(0), Type(STRING) {}
			DataNode(const eastl::string& str) : String(str), Number(0), Type(STRING) {}
			DataNode(double num) : String(), Number(num), Type(NUMBER) {}
			//DataNode& operator=(const eastl::string& str) { Destroy(); Type = STRING; String = str; }
			DataNode& operator=(double num) { Destroy(); Type = NUMBER; Number = num; }
			DataNode& operator=(const DataNode& n);

			bool operator==(const eastl::string& str) const { return Type == STRING && String == str; }
			bool operator==(const char* str) const { return Type == STRING && String == str; }
			bool operator==(double n) const { return Type == NUMBER && Number == n; }

			operator const char*() { if (Type == STRING) return String.c_str(); else return ""; }

			virtual ~DataNode() { Destroy(); }

			DataNode& operator[](const char* str);
			DataNode& operator[](const eastl::string& str) { return operator[](str.c_str()); }

			virtual DataNode* Create() const { return new DataNode; }

			virtual const char* Parse(const char*) { return 0; }
			virtual eastl::string Encode() const { return ""; }

      void Destroy();
		};

	} /// Structures

	/// Converts a DataNode to an object. Returns true on success
	template <typename T>
	bool NodeToObject(T& obj, const GTL::Structures::DataNode* node);

	///************************************************************************/
	///* Implementations                                                      */
	///************************************************************************/

	namespace Structures
	{

    class DataNodeGEncode : public DataNode
    {
    public:
			virtual ~DataNodeGEncode() {}

      virtual const char* Parse(const char* str);
			virtual eastl::string Encode() const  { return ""; }
			virtual DataNode* Create() const { return new DataNodeGEncode; }
    private:
      const char* ParseDict(const char* str);
      const char* ParseNumber(const char* str);
      const char* ParseString(const char* str);
      const char* ParseList(const char* str);
    };

    class DataNodeWilson : public DataNode
    {
    public:
			DataNodeWilson() : DataNode() {}
			DataNodeWilson(const char* str) : DataNode(str) {}
			DataNodeWilson(const eastl::string& str) : DataNode(str) {}
			DataNodeWilson(double num) : DataNode(num) {}
			virtual ~DataNodeWilson() {}

      virtual const char* Parse(const char* str); /// v
			virtual eastl::string Encode() const;
			virtual DataNode* Create() const { return new DataNodeWilson; }
    private:
      const char* ParseDict(const char* str); /// v
      const char* ParseNumber(const char* str); /// v
      const char* ParseString(const char* str); /// v
      const char* ParseList(const char* str); /// v
      const char* ParseWordString(const char* str); /// v
      const char* StripWhitespace(const char* str); /// v
    };
   
  }
}


/*
#include "ArrayStack.h"
template <class T> class NTreeNode
{
public:
  typedef std::list<T>::iterator Position;

  NTreeNode<T>( T data );

  NTreeNode<T> *PrependChild( NTreeNode<T> *node );
  NTreeNode<T> *AppendChild( NTreeNode<T> *node );
  NTreeNode<T> *InsertChildAfterIndex( NTreeNode<T> *node, int index );
  NTreeNode<T> *InsertChildBeforeIndex( NTreeNode<T> *node, int index );
  NTreeNode<T> *RemoveChild( Position position );
  NTreeNode<T> *RemoveChild( int index );
  Position InsertAfter( NTreeNode<T> *node, Position position );
  Position InsertBefore( NTreeNode<T> *node, Position position );
  int GetNumChildren();
  Position GetChildPosition( int childNum );
  NTreeNode<T> *GetChild( int childNum );
  NTreeNode<T> *GetChild( Position position );
  int GetIndexRelativeToParent();
  T GetItem();
  NTreeNode<T> *GetParent();
  NTreeNode<T> *GetRoot();
  NTreeNode<T> *GetNextSibling();
  void Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth );
  NTreeNode<T> *ReentrantTraversalGetFirst( int maxTreeDepth );
  NTreeNode<T> *ReentrantTraversalGetNext( void );

protected:
  std::list<NTreeNode<T> * > *list;
  T data;
  NTreeNode<T> *parent;
  ArrayStack<NTreeNode<T> *> *reentrantStack;
};

template <class T>
NTreeNode<T>::NTreeNode( T data )
{
  list = new std::list<NTreeNode<T> * >;
  this->data = data;
  this->parent = NULL;
  this->reentrantStack = NULL;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::PrependChild( NTreeNode<T> *node )
{
  node->parent = this;
  return list->GetItemAtPosition( list->InsertAtHead( node ) );
}

template <class T>
NTreeNode<T> *NTreeNode<T>::AppendChild( NTreeNode<T> *node )
{
  node->parent = this;
  return list->GetItemAtPosition( list->InsertAtTail( node ) );
}

template <class T>
NTreeNode<T> *NTreeNode<T>::InsertChildAfterIndex( NTreeNode<T> *node, int index )
{
  node->parent = this;
  if( index < 0 )
  {
    // if out of range in the negative direction, prepend
    this->PrependChild( node );
  }
  else if( index > list->GetNumItems() - 1 )
  {
    // if out of range, just append.
    this->AppendChild( node );
  }
  else
  {
    Position pos;
    pos = list->GetPositionAtIndex( index );
    list->InsertAfter( node, pos );
  }
  return node;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::InsertChildBeforeIndex( NTreeNode<T> *node, int index )
{
  node->parent = this;
  if( index < 0 )
  {
    // if out of range in the negative direction, prepend
    this->PrependChild( node );
  }
  else if( index > list->GetNumItems() - 1 )
  {
    // if out of range, just append.
    this->AppendChild( node );
  }
  else
  {
    Position pos;
    pos = list->GetPositionAtIndex( index );
    list->InsertBefore( node, pos );
  }
  return node;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::RemoveChild( Position position )
{
  NTreeNode<T> **node = ( NTreeNode<T> ** )( void * )position;
  ( *node )->parent = NULL;
  return list->Remove( position );
}

template <class T>
NTreeNode<T> *NTreeNode<T>::RemoveChild( int index )
{
  Position position = list->GetPositionAtIndex( index );
  NTreeNode<T> **node = ( NTreeNode<T> ** )( void * )position;
  ( *node )->parent = NULL;
  return list->Remove( position );
}

template <class T>
Position NTreeNode<T>::InsertAfter( NTreeNode<T> *node, Position position )
{
  node->parent = this;
  return list->InsertAfter( node, position );
}

template <class T>
Position NTreeNode<T>::InsertBefore( NTreeNode<T> *node, Position position )
{
  node->parent = this;
  return list->InsertBefore( node, position );
}

template <class T>
int NTreeNode<T>::GetNumChildren()
{
  return list->GetNumItems();
}

template <class T>
Position NTreeNode<T>::GetChildPosition( int childNum )
{
  return list->GetPositionAtIndex( childNum );
}

template <class T>
NTreeNode<T> *NTreeNode<T>::GetChild( int childNum )
{
  return list->GetItemAtIndex( childNum );
}

template <class T>
NTreeNode<T> *NTreeNode<T>::GetChild( Position position )
{
  return list->GetItemAtIndex( position );
}

template <class T>	
int NTreeNode<T>::GetIndexRelativeToParent()
{
  if( !parent )
  {
    GTL_ASSERT( 0 ); // hack
    return -1;
  }
  GListIterator<NTreeNode<T> *> iterator( parent->list );
  int i;
  for( i = 0, iterator.GotoHead(); !iterator.AtEnd(); iterator++, i++ )
  {
    if( iterator.GetCurrent() == this )
    {
      return i;
    }
  }
  GTL_ASSERT( 0 ); // hack
  return -1;
}

template <class T>
T NTreeNode<T>::GetItem()
{
  return data;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::GetParent()
{
  return parent;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::GetRoot()
{
  NTreeNode<T> *node;
  node = this;
  while( node->GetParent() )
  {
    node = node->GetParent();
  }
  return node;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::GetNextSibling()
{
  int currentID, siblingID;
  NTreeNode<T> *parent;
  parent = this->GetParent();
  if( !parent )
  {
    return NULL;
  }
  currentID = this->GetIndexRelativeToParent();
  siblingID = currentID + 1;
  if( siblingID < parent->GetNumChildren() )
  {
    return parent->GetChild( siblingID );
  }
  else
  {
    return NULL;
  }
}

template <class T>
void NTreeNode<T>::Traverse( void (*VisitFunc)( T, int depth ), int maxTreeDepth )
{
  ArrayStack<NTreeNode<T> *> stack( maxTreeDepth );
  NTreeNode<T> *current, *nextSibling;

  stack.Push( this );	
  Visit( this->GetItem(), 0 );
  while( !stack.IsEmpty() )
  {
    current = stack.Pop();
    if( current->GetNumChildren() > 0 )
    {
      stack.Push( current );
      stack.Push( current->GetChild( 0 ) );
      Visit( current->GetChild( 0 )->GetItem(), stack.GetDepth() - 1 );
    }
    else
    {
      while( !stack.IsEmpty() && !( nextSibling = current->GetNextSibling() ) )
      {
        current = stack.Pop();
      }
      if( !stack.IsEmpty() )
      {
        stack.Push( nextSibling );
        Visit( nextSibling->GetItem(), stack.GetDepth() - 1 );
      }	
    }
  }
}

template <class T>
NTreeNode<T> *NTreeNode<T>::ReentrantTraversalGetFirst( int maxTreeDepth )
{
  if( reentrantStack )
  {
    delete reentrantStack;
  }
  reentrantStack = new ArrayStack<NTreeNode<T> *>( maxTreeDepth );
  reentrantStack->Push( this );
  return this;
}

template <class T>
NTreeNode<T> *NTreeNode<T>::ReentrantTraversalGetNext( void )
{
  NTreeNode<T> *current, *nextSibling;

  while( !reentrantStack->IsEmpty() )
  {
    current = reentrantStack->Pop();
    if( current->GetNumChildren() > 0 )
    {
      reentrantStack->Push( current );
      reentrantStack->Push( current->GetChild( 0 ) );
      return current->GetChild( 0 );
    }
    else
    {
      while( !reentrantStack->IsEmpty() && !( nextSibling = current->GetNextSibling() ) )
      {
        current = reentrantStack->Pop();
      }
      if( !reentrantStack->IsEmpty() )
      {
        reentrantStack->Push( nextSibling );
        return nextSibling;
      }	
    }
  }
  delete reentrantStack;
  reentrantStack = NULL;
  return NULL;
}
*/
#endif /* __TREE_H__ */
